package me.ree.zkproduct.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Getter;

import java.io.IOException;
import java.util.List;
import java.util.Set;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
import static com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES;
import static com.fasterxml.jackson.databind.DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
import static com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS;

public class JsonUtil {

    @Getter
    private final static ObjectMapper mapper;

//    @Getter
//    private final static Gson gson;

    static {
        mapper = new ObjectMapper();
        mapper.configure(FAIL_ON_EMPTY_BEANS, false);
        mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(ALLOW_UNQUOTED_FIELD_NAMES, true);
        mapper.configure(ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        mapper.setSerializationInclusion(NON_NULL);
        mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

//        gson = new Gson();
    }

    public static <T> byte[] toJsonAsBytes(T o) throws IOException {
        return mapper.writeValueAsBytes(o);
    }

    public static <T> String toJson(T o) {
        try {
            return mapper.writeValueAsString(o);
        } catch (IOException e) {
            throw new RuntimeException("Object to json error:", e);
        }
    }

    public static <T> String toJson(T o, String defaultVal) {
        if (o == null) {
            return defaultVal;
        }

        try {
            return mapper.writeValueAsString(o);
        } catch (IOException e) {
            throw new RuntimeException("Object to json error:", e);
        }
    }

    /**
     * @param json: 不能是null
     * @param clazz
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> T toObject(String json, Class<T> clazz) throws IOException {
        return mapper.readValue(json, clazz);
    }

    public static <T> T toObject(byte[] json, Class<T> clazz) throws IOException {
        return mapper.readValue(json, clazz);
    }

    public static <T> T toObject(String json, TypeReference<T> typeRef) throws IOException {
        return mapper.readValue(json, typeRef);
    }

    public static <T> T toObject(byte[] json, TypeReference<T> typeRef) throws IOException {
        return mapper.readValue(json, typeRef);
    }

    public static <T> T toObject(String json, JavaType type) throws IOException {
        return mapper.readValue(json, type);
    }

    public static <T> T toObject(byte[] json, JavaType type) throws IOException {
        return mapper.readValue(json, type);
    }

    public static <T> List<T> toObjectList(String json, Class<T> clazz) throws IOException {
        JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, clazz);
        return mapper.readValue(json, javaType);
    }

    public static <T> List<T> toObjectList(byte[] json, Class<T> clazz) throws IOException {
        JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, clazz);
        return mapper.readValue(json, javaType);
    }

    public static <T> Set<T> toObjectSet(String json, Class<T> clazz) throws IOException {
        JavaType javaType = mapper.getTypeFactory().constructParametricType(Set.class, clazz);
        return mapper.readValue(json, javaType);
    }

    public static ObjectNode createNode() {
        return mapper.createObjectNode();
    }

    public static <T1, T2> T2 convert(T1 param, Class<T2> clazz) throws IOException {
        String s = JsonUtil.toJson(param);
        return JsonUtil.toObject(s, clazz);
    }

//    /**
//     * ==========================Gson序列化工具============================
//     **/
//
//    public static <T> String toGsonJson(T o) {
//        try {
//            return gson.toJson(o);
//        } catch (Exception e) {
//            throw new RuntimeException("Object to gson json error:", e);
//        }
//    }
//
//    public static <T> List<T> toGsonObjectList(String json, Class<T[]> clazz) {
//        T[] arr = new Gson().fromJson(json, clazz);
//        return Arrays.asList(arr);
//    }
//
//    public static <T> T toGsonObject(String json, Class<T> clazz) {
//        return new Gson().fromJson(json, clazz);
//    }
}
